Fix KeyAlreadyPresent error when AoT is extended by a dotted-key header after an unrelated table#529
Conversation
…er after an unrelated table
When a dotted-key header like [fruit.apple.texture] appears after an
unrelated table following an [[fruit]] array-of-tables, the parser
creates a super-table chain that is appended to the document body with
the same root key ('fruit') as the existing AoT. Container.append
saw a table (not an explicit AoT element) after an AoT and raised
KeyAlreadyPresent.
The fix walks the super-table and does a deep merge into the last
element of the existing AoT, which is where the TOML spec implicitly
places such extensions.
|
Is this better or worse than #498? Why? |
|
Thanks for pointing at #498. The semantic direction is the same, but this branch is intended to be a stricter superset: #498 appends the immediate super-table children into the last AoT element, while this branch recursively merges super-table children, so it also keeps existing nested table contents such as While checking that comparison, I found this branch was too permissive for invalid redefinitions: So compared with #498: better on recursive merge coverage after the latest commit, similar caveat on layout normalization. #498 also adds a README limitations note for that caveat; I can add the same note here if you would prefer this PR to carry the documentation change too. Validation run locally: |
I am just a passer by, a maintainer will have to decide which (if either) pull request to accept and what the docs should say. But IMO if code is knowingly breaking tomlkit's promises about preserving element ordering - that wants writing down. |
|
I agree. I added a short README limitation note in 854c2fb documenting that this out-of-order AoT sub-table case preserves the data but normalizes the sub-table's physical position when serialized. Checked locally:
|
Fixes #261.
When a dotted-key header like
[fruit.apple.texture]appears after an unrelated table following an[[fruit]]array-of-tables, the parser creates a super-table chain thatContainer.appendreceives with the same root key (fruit) as the existing AoT. Since the new item is a table (not an explicit AoT element), append previously raisedKeyAlreadyPresent.Example that was rejected before this fix:
The fix walks the super-table produced by the parser and does a deep merge of its children into the last element of the existing AoT — the TOML spec implicitly places such dotted-key extensions under the most recent table/array-table header.
The rendering order of unrelated tables interspersed with AoT extensions is not preserved (this is a pre-existing style-preservation limitation), but the parsed data is semantically correct and round-trips.